package com.bolt.support.json.jackjson.mvc.advice;

import com.bolt.support.json.jackjson.annotation.JacksonJsonFilter;
import com.bolt.support.json.jackjson.annotation.JacksonJsonView;
import com.bolt.support.json.jackjson.filter.DynamicFilterProvider;
import com.bolt.support.json.jackjson.filter.JacksonBeanPropertyFilter;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 勉强完成类fastjson 的spring mvc 的jsonview 功能。由于无 法完成
 * 动态注删 filter ,需要在返回类上加 @JsonFilter("JacksonFilter") 注解
 * 不加，无法动态指定过滤
 */
@Order
@ControllerAdvice
public class JsonViewResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.hasMethodAnnotation(JacksonJsonView.class);
    }

    private MappingJacksonValue getOrCreateContainer(Object body) {
        return (body instanceof MappingJacksonValue ? (MappingJacksonValue) body : new MappingJacksonValue(body));

    }

    @Override
    public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        MappingJacksonValue container = getOrCreateContainer(body);
        beforeBodyWriteInternal(container, selectedContentType, returnType, request, response);
        return container;
    }


    protected void beforeBodyWriteInternal(MappingJacksonValue container, MediaType contentType,
                                           MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
        JacksonJsonView annotation = returnType.getMethodAnnotation(JacksonJsonView.class);
        JacksonJsonFilter[] include = annotation.include();
        JacksonJsonFilter[] exclude = annotation.exclude();
        JacksonBeanPropertyFilter filter = new JacksonBeanPropertyFilter();
        for (JacksonJsonFilter item : include) {
            filter.include(item.clazz(), item.props());
        }
        for (JacksonJsonFilter item : exclude) {
            filter.exclude(item.clazz(), item.props());
        }
        DynamicFilterProvider filters = new DynamicFilterProvider(filter);
        container.setFilters(filters);
    }
}